/*
 * Name        : NetworkHttpEngine.java
 * Classes     : NetworkHttpEngine
 * Version     : 1.0
 * Date        : 2013-08-29
 *
 * Copyright 2013 CMCC.  All rights reserved.
 * This material, including documentation and any related computer
 * programs, is protected by copyright controlled by CMCC.  All
 * rights are reserved.  Copying, including reproducing, storing,
 * adapting or translating, any or all of this material requires the
 * prior written consent of CMCC.  This material also contains
 * confidential information which may not be disclosed to others
 * without the prior written consent of CMCC.
 */

package com.xgkj.diyiketang.http;

import com.xgkj.diyiketang.util.PalLog;

import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.util.EntityUtils;
import com.xgkj.diyiketang.http.HttpEvent.HttpEventType;
import com.xgkj.diyiketang.http.HttpEvent.HttpErrorCode;




/**
 * Class Name : NetworkHttpEngine
 * Author     : Huang xiao qing
 * Date       : 13-9-3
 * Description : provide network access of HTTP
 */
public class NetworkHttpEngine extends HttpEngine {

	private int mConnectionTimeOut;
	private int mSocketTimeOut;
	private boolean mFollowRedirect;

	private DefaultHttpClient mHttpClient;

	private static final int DEFAULT_CONN_TIMEOUT   = 20 * 1000;
	private static final int DEFAULT_SOCKET_TIMEOUT = 20 * 1000;
	static String JSESSIONID = null;

	protected NetworkHttpEngine() {
		this(DEFAULT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT, true);
	}

	private NetworkHttpEngine(int connTimeOut, int socketTimeout, boolean followRedirect) {
		mConnectionTimeOut = connTimeOut;
		mSocketTimeOut = socketTimeout;
		mFollowRedirect = followRedirect;
		
		mHttpClient = new DefaultHttpClient();
		setHttpClientParams();
	}
	
	
	@Override
	public void setConnectionTimeOut(int timeOut) {
		mConnectionTimeOut = timeOut;
		setHttpClientParams();
	}

	/**
	 * HTTP GET method
	 * @param url URL
	 * @param headParams HTTP head
	 */
	@Override
	public void sendGet(String url, Map<String, String> headParams) {
		if (url == null) {
			throw new IllegalArgumentException("URL is invalid.");
		}
		
		HttpEvent event = null;
		try {
			HttpGet request = createGetRequest(url, headParams);
			HttpResponse response = mHttpClient.execute(request);
			event = handleResponse(response);
		} catch (ClientProtocolException e) {
			event = new HttpEvent(HttpEventType.HTTP_EVENT_FAILED, HttpErrorCode.HTTP_ERROR_GENERAL);
			e.printStackTrace();
		} catch (ConnectTimeoutException e) {
			event = new HttpEvent(HttpEventType.HTTP_EVENT_FAILED, HttpErrorCode.HTTP_ERROR_TIMEOUT);
			e.printStackTrace();
		} catch (IOException e) {
			event = new HttpEvent(HttpEventType.HTTP_EVENT_FAILED, HttpErrorCode.HTTP_ERROR_GENERAL);
			e.printStackTrace();
		} catch (Exception e) {
			event = new HttpEvent(HttpEventType.HTTP_EVENT_FAILED, HttpErrorCode.HTTP_ERROR_GENERAL);
		}
		notifyListener(event);
	}

	private void setHttpClientParams() {
		HttpParams httpParams = new BasicHttpParams();

		HttpConnectionParams.setConnectionTimeout(httpParams, mConnectionTimeOut);
		HttpConnectionParams.setSoTimeout(httpParams, mSocketTimeOut);

		HttpClientParams.setRedirecting(httpParams, mFollowRedirect);
		mHttpClient.setParams(httpParams);
	}

	/**
	 * HTTP POST method
	 * @param url URL
	 * @param headParams HTTP head
	 */
	@Override
	public void sendPost(String url, byte[] data, Map<String, String> formParams, Map<String, String> headParams) {
		if (url == null) {
			throw new IllegalArgumentException("URL is invalid.");
		}

		HttpEvent event = null;
		try {
			
			HttpPost post = createPostRequest(url, data, formParams, headParams);
			HttpResponse response = mHttpClient.execute(post);
			JSESSIONID = getCookieSession(response);
			PalLog.d("session", JSESSIONID);
			event = handleResponse(response);
			
		} catch (ConnectTimeoutException e) {
			event = new HttpEvent(HttpEventType.HTTP_EVENT_FAILED, HttpErrorCode.HTTP_ERROR_TIMEOUT);
			e.printStackTrace();
		} catch (ClientProtocolException e) {
			event = new HttpEvent(HttpEventType.HTTP_EVENT_FAILED, HttpErrorCode.HTTP_ERROR_GENERAL);
			e.printStackTrace();
		} catch (IOException e) {
			event = new HttpEvent(HttpEventType.HTTP_EVENT_FAILED, HttpErrorCode.HTTP_ERROR_CONNECT_FAIL);
			e.printStackTrace();
		} catch (Exception e) {
			event = new HttpEvent(HttpEventType.HTTP_EVENT_FAILED, HttpErrorCode.HTTP_ERROR_GENERAL);
		}
		notifyListener(event);
	}

	private HttpGet createGetRequest(String url, Map<String, String> headParams) {
		HttpGet result = new HttpGet(url);
		addHead(result, headParams);
		return result;
	}

	private HttpEvent handleResponse(HttpResponse response) {
		HttpEvent result = null;
		if (response != null) {
			StatusLine statusLine = response.getStatusLine();
			if (statusLine != null) {
				PalLog.e("NetworkHttpEngine", statusLine.getStatusCode() + "");
				if (statusLine.getStatusCode() == HttpStatus.SC_OK) {
					HttpEntity entity = response.getEntity();
					if (entity != null) {
						byte[] content = readData(entity);
						if (content != null && content.length > 0) {
							result = new HttpEvent(HttpEventType.HTTP_EVENT_SUCCESS, HttpStatus.SC_OK, parseHeaders(response), content);
						} else {
							result = new HttpEvent(HttpEventType.HTTP_EVENT_SUCCESS, HttpStatus.SC_OK, parseHeaders(response), content);
						}
					} else {
						result = new HttpEvent(HttpEventType.HTTP_EVENT_SUCCESS, HttpStatus.SC_OK, parseHeaders(response));
					}
				} else {
					result = new HttpEvent(HttpEventType.HTTP_EVENT_FAILED, HttpErrorCode.HTTP_ERROR_RESP_CODE_FAIL);
					result.setHttpRespCode(statusLine.getStatusCode());
				}
			}
		}
		if (result == null) {
			result = new HttpEvent(HttpEventType.HTTP_EVENT_FAILED, HttpErrorCode.HTTP_ERROR_GENERAL);
		}
		return result;
	}

	private HashMap<String, String> parseHeaders(HttpResponse response) {
		HashMap<String, String> result = null;
		Header[] headers = response.getAllHeaders();
		if (headers != null) {
			result = new HashMap<String, String>();
			for (int i = 0; i < headers.length; i++) {
				Header header = headers[i];
				result.put(header.getName(), header.getValue());
			}
		}
		return result;
	}

	private byte[] readData(HttpEntity entity) {
		byte[] result = null;
		if (entity != null) {
			try {
				result = EntityUtils.toByteArray(entity);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return result;
	}

	private HttpPost createPostRequest(String url, byte[] data, Map<String, String> formParams, Map<String, String> headParams) {
		HttpPost result = new HttpPost(url);
		if (formParams != null && !formParams.isEmpty()) {
			// UrlEncodedFormEntity urlEntity =
			// createUrlEncodedFormEntity(formParams, HTTP.UTF_8);
			MultipartEntity mulEntity = createMultiPartEntity(formParams);
			result.setEntity(mulEntity);
		}
		
		if (data != null && data.length > 0) {
			ByteArrayEntity entity = new ByteArrayEntity(data);
			result.setEntity(entity);
		}
		addHead(result, headParams);
		return result;
	}

	private void addHead(HttpUriRequest request, Map<String, String> headParams) {
		if (headParams != null && !headParams.isEmpty()) {
			Iterator<Entry<String, String>> iterator = headParams.entrySet().iterator();
			while (iterator.hasNext()) {
				Entry<String, String> entry = (Entry<String, String>) iterator.next();
				request.addHeader(entry.getKey(), entry.getValue());
			}
		}
		request.setHeader("cookie", JSESSIONID);
	}

	private UrlEncodedFormEntity createUrlEncodedFormEntity(Map<String, String> formParams, String encode) throws UnsupportedEncodingException {
		ArrayList<NameValuePair> nvps = new ArrayList<NameValuePair>();
		Iterator<Entry<String, String>> iterator = formParams.entrySet().iterator();
		while (iterator.hasNext()) {
			Entry<String, String> entry = (Entry<String, String>) iterator.next();
			nvps.add(new BasicNameValuePair((String) entry.getKey(), (String) entry.getValue()));
		}
		return new UrlEncodedFormEntity(nvps, encode);
	}
	
	private MultipartEntity createMultiPartEntity(Map<String, String> multipartdata){
		MultipartEntity mulEntity = new MultipartEntity();
		Iterator<Entry<String, String>> iterator = multipartdata.entrySet().iterator();
		while(iterator.hasNext()){
			Entry<String, String> entry = (Entry<String, String>) iterator.next();
			File file = new File(entry.getValue());
			mulEntity.addPart(entry.getKey(), new FileBody(file));
		}
		return mulEntity;
	}
	
	private String getCookieSession(HttpResponse http) throws IOException{
		Header[] cookis = http.getHeaders("Set-Cookie");
		if(cookis.length>0){
		System.out.println(cookis[0].toString());
		String cookString = cookis[0].getValue();
		if(cookString != null && cookString.indexOf("JSESSIONID") >=0){
			String[] items = cookString.split(";");
			for (int i = 0; i < items.length; i++) {
				if(items[i].trim().startsWith("JSESSIONID")){
					return items[i].trim();
				}
			}
		}
		}
		return JSESSIONID;
	}

}
